#include "RAT_Matrix33.h"

namespace RAT_ENGINE
{

	/// <summary>
	/// Overrides the arithmic operator *, to calculate the multiplication of two matrices.
	/// </summary>
	/// <param name="argMatrix">The matrix that is calculated with.</param>
	/// <returns> The product RAT_Matrix33 </returns>
	RAT_Matrix33 RAT_Matrix33::operator* (const RAT_Matrix33& argMatrix) const
	{
		//Initializes the matrix that is to be returned.
		RAT_Matrix33 matrixResult;
		
		//Calculates the first row of the new matrix.
		matrixResult.R11 = R11 * argMatrix.R11 + R12 * argMatrix.R12 + R13 * argMatrix.R13;
		matrixResult.R12 = R11 * argMatrix.R21 + R12 * argMatrix.R22 + R13 * argMatrix.R23;
		matrixResult.R13 = R11 * argMatrix.R31 + R12 * argMatrix.R32 + R13 * argMatrix.R33;

		//Calculates the second row of the new matrix.
		matrixResult.R21 = R21 * argMatrix.R11 + R22 * argMatrix.R12 + R23 * argMatrix.R13;
		matrixResult.R22 = R21 * argMatrix.R21 + R22 * argMatrix.R22 + R23 * argMatrix.R23;
		matrixResult.R23 = R21 * argMatrix.R31 + R22 * argMatrix.R32 + R23 * argMatrix.R33;
	
		//Calculates the third row of the new matrix.
		matrixResult.R31 = R31 * argMatrix.R11 + R32 * argMatrix.R12 + R33 * argMatrix.R13;
		matrixResult.R32 = R31 * argMatrix.R21 + R32 * argMatrix.R22 + R33 * argMatrix.R23;
		matrixResult.R33 = R31 * argMatrix.R31 + R32 * argMatrix.R32 + R33 * argMatrix.R33;
																						 
		//Returns matrixResult.
		return matrixResult;
	}

	/// <summary>
	/// Overrides the arithmic operator *, to scale this matrix.
	/// </summary>
	/// <param name="argScale">The matrix that is calculated with.</param>
	/// <returns> The product RAT_Matrix33 </returns>
	RAT_Matrix33 RAT_Matrix33::operator* (const float& argScale) const
	{
		//Initializes the matrix that is to be returned.
		RAT_Matrix33 matrixResult;
		
		//Calculates the first row of the new matrix.
		matrixResult.R11 = R11 * argScale;
		matrixResult.R12 = R12 * argScale;
		matrixResult.R13 = R13 * argScale;

		//Calculates the second row of the new matrix.
		matrixResult.R21 = R21 * argScale;
		matrixResult.R22 = R22 * argScale;
		matrixResult.R23 = R23 * argScale;
	
		//Calculates the third row of the new matrix.
		matrixResult.R31 = R31 * argScale;
		matrixResult.R32 = R32 * argScale;
		matrixResult.R33 = R33 * argScale;
																						 
		//Returns matrixResult.
		return matrixResult;
	}


	/// <summary>
	/// Overrides the compound operator *=, to calculate the multiplication of two matrices.
	/// </summary>
	/// <param name="argMatrix">The matrix that is calculated with.</param>
	/// <returns> The product RAT_Matrix33 </returns>
	RAT_Matrix33 RAT_Matrix33::operator*= (const RAT_Matrix33& argMatrix) const
	{
		//Initializes the matrix that is to be returned.
		RAT_Matrix33 matrixResult;
		
		//Calculates the first row of the new matrix.
		matrixResult.R11 = R11 * argMatrix.R11 + R12 * argMatrix.R12 + R13 * argMatrix.R13;
		matrixResult.R12 = R11 * argMatrix.R21 + R12 * argMatrix.R22 + R13 * argMatrix.R23;
		matrixResult.R13 = R11 * argMatrix.R31 + R12 * argMatrix.R32 + R13 * argMatrix.R33;

		//Calculates the second row of the new matrix.
		matrixResult.R21 = R21 * argMatrix.R11 + R22 * argMatrix.R12 + R23 * argMatrix.R13;
		matrixResult.R22 = R21 * argMatrix.R21 + R22 * argMatrix.R22 + R23 * argMatrix.R23;
		matrixResult.R23 = R21 * argMatrix.R31 + R22 * argMatrix.R32 + R23 * argMatrix.R33;
	
		//Calculates the third row of the new matrix.
		matrixResult.R31 = R31 * argMatrix.R11 + R32 * argMatrix.R12 + R33 * argMatrix.R13;
		matrixResult.R32 = R31 * argMatrix.R21 + R32 * argMatrix.R22 + R33 * argMatrix.R23;
		matrixResult.R33 = R31 * argMatrix.R31 + R32 * argMatrix.R32 + R33 * argMatrix.R33;
																						 
		//Returns matrixResult.
		return matrixResult;
	}

	/// <summary>
	/// Overrides the compound operator *, to scale this matrix.
	/// </summary>
	/// <param name="argScale">The matrix that is calculated with.</param>
	/// <returns> The product RAT_Matrix33 </returns>
	RAT_Matrix33 RAT_Matrix33::operator*= (const float& argScale) const
	{
		//Initializes the matrix that is to be returned.
		RAT_Matrix33 matrixResult;
		
		//Calculates the first row of the new matrix.
		matrixResult.R11 = R11 * argScale;
		matrixResult.R12 = R12 * argScale;
		matrixResult.R13 = R13 * argScale;

		//Calculates the second row of the new matrix.
		matrixResult.R21 = R21 * argScale;
		matrixResult.R22 = R22 * argScale;
		matrixResult.R23 = R23 * argScale;
	
		//Calculates the third row of the new matrix.
		matrixResult.R31 = R31 * argScale;
		matrixResult.R32 = R32 * argScale;
		matrixResult.R33 = R33 * argScale;
																						 
		//Returns matrixResult.
		return matrixResult;
	}

	/// <summary>
	/// Overrides the relational operator ==, to compare two RAT_Matrix33.
	/// </summary>
	/// <param name="argMatrix>The matrix that this is compared with.</param>
	/// <returns>A boolean that determines if this and argVector are equal.</returns>
	bool RAT_Matrix33::operator== (const RAT_Matrix33& argMatrix) const
	{
		return R11 == argMatrix.R11 &&
			   R12 == argMatrix.R12 &&
			   R13 == argMatrix.R13 &&
			   R21 == argMatrix.R21 &&
			   R22 == argMatrix.R22 &&
			   R23 == argMatrix.R23 &&
			   R31 == argMatrix.R31 &&
			   R32 == argMatrix.R32 &&
			   R33 == argMatrix.R33;
	}

	/// <summary>
	/// Overrides the relational operator !=, to compare two RAT_Matrix33.
	/// </summary>
	/// <param name="argMatrix>The matrix that this is compared with.</param>
	/// <returns>A boolean that determines if this and argMatrix are not equal.</returns>
	bool RAT_Matrix33::operator!= (const RAT_Matrix33& argMatrix) const
	{
		return R11 != argMatrix.R11 &&
			   R12 != argMatrix.R12 &&
			   R13 != argMatrix.R13 &&
			   R21 != argMatrix.R21 &&
			   R22 != argMatrix.R22 &&
			   R23 != argMatrix.R23 &&
			   R31 != argMatrix.R31 &&
			   R32 != argMatrix.R32 &&
			   R33 != argMatrix.R33;
	}

	
	///<summary>
	///Calculates the determinant of this matrix.
	///</summary>
	///<returns>The determinant of this matrix.</returns>
	float RAT_Matrix33::Determinant() const
	{
		//Initializes the float that is to be returned.
		float determinant;
		
		float determinantR11 = R11 * (R22 * R33 - R23 * R32);
		float determinantR21 = R21 * (R12 * R33 - R13 * R32);
		float determinantR31 = R31 * (R12 * R23 - R13 * R22);

		determinant = determinantR11 - determinantR21 + determinantR31;

		//Returns the determinant.
		return determinant;
	}
	
	///<summary>
	///Calculates the inverse of this matrix.
	///</summary>
	///<returns>The inverse of this matrix</returns>
	RAT_Matrix33 RAT_Matrix33::Inverse() const
	{
		//Initializes the matrix that is to be returned.
		RAT_Matrix33 matrixResult = RATIDENTITYMATRIX33;

		//Initializes the helper matrix.
		RAT_Matrix33 tmpMatrix = *this;

		//Initializes a helper float.
		float tmpFloat;

		//Calculates the first row.
		tmpFloat = tmpMatrix.R11;
		tmpMatrix.R11	 /= tmpFloat;
		tmpMatrix.R12	 /= tmpFloat;
		tmpMatrix.R13	 /= tmpFloat;
		matrixResult.R11 /= tmpFloat;
		matrixResult.R12 /= tmpFloat;
		matrixResult.R13 /= tmpFloat;

		//Calculates the second row using the first row.
		tmpFloat = tmpMatrix.R21;
		tmpMatrix.R21	 -= tmpFloat * tmpMatrix.R11;
		tmpMatrix.R22	 -= tmpFloat * tmpMatrix.R12;
		tmpMatrix.R23	 -= tmpFloat * tmpMatrix.R13;
		matrixResult.R21 -= tmpFloat * matrixResult.R11;
		matrixResult.R22 -= tmpFloat * matrixResult.R12;
		matrixResult.R23 -= tmpFloat * matrixResult.R13;
		
		//Calculates the third row using the first row.
		tmpFloat = tmpMatrix.R31;
		tmpMatrix.R31	 -= tmpFloat * tmpMatrix.R11;
		tmpMatrix.R32	 -= tmpFloat * tmpMatrix.R12;
		tmpMatrix.R33	 -= tmpFloat * tmpMatrix.R13;
		matrixResult.R31 -= tmpFloat * matrixResult.R11;
		matrixResult.R32 -= tmpFloat * matrixResult.R12;
		matrixResult.R33 -= tmpFloat * matrixResult.R13;

		
		//Calculates the second row.
		tmpFloat = tmpMatrix.R22;
		tmpMatrix.R21	 /= tmpFloat;
		tmpMatrix.R22	 /= tmpFloat;
		tmpMatrix.R23	 /= tmpFloat;
		matrixResult.R21 /= tmpFloat;
		matrixResult.R22 /= tmpFloat;
		matrixResult.R23 /= tmpFloat;

		//Calculates the first row using the second row.
		tmpFloat = tmpMatrix.R12;
		tmpMatrix.R11	 -= tmpFloat * tmpMatrix.R21;
		tmpMatrix.R12	 -= tmpFloat * tmpMatrix.R22;
		tmpMatrix.R13	 -= tmpFloat * tmpMatrix.R23;
		matrixResult.R11 -= tmpFloat * matrixResult.R21;
		matrixResult.R12 -= tmpFloat * matrixResult.R22;
		matrixResult.R13 -= tmpFloat * matrixResult.R23;
		
		//Calculates the third row using the second row.
		tmpFloat = tmpMatrix.R32;
		tmpMatrix.R31	 -= tmpFloat * tmpMatrix.R21;
		tmpMatrix.R32	 -= tmpFloat * tmpMatrix.R22;
		tmpMatrix.R33	 -= tmpFloat * tmpMatrix.R23;
		matrixResult.R31 -= tmpFloat * matrixResult.R21;
		matrixResult.R32 -= tmpFloat * matrixResult.R22;
		matrixResult.R33 -= tmpFloat * matrixResult.R23;
		

		//Calculates the third row.
		tmpFloat = tmpMatrix.R33;
		tmpMatrix.R31	 /= tmpFloat;
		tmpMatrix.R32	 /= tmpFloat;
		tmpMatrix.R33	 /= tmpFloat;
		matrixResult.R31 /= tmpFloat;
		matrixResult.R32 /= tmpFloat;
		matrixResult.R33 /= tmpFloat;

		//Calculates the first row using the third row.
		tmpFloat = tmpMatrix.R13;
		tmpMatrix.R11	 -= tmpFloat * tmpMatrix.R31;
		tmpMatrix.R12	 -= tmpFloat * tmpMatrix.R32;
		tmpMatrix.R13	 -= tmpFloat * tmpMatrix.R33;
		matrixResult.R11 -= tmpFloat * matrixResult.R31;
		matrixResult.R12 -= tmpFloat * matrixResult.R32;
		matrixResult.R13 -= tmpFloat * matrixResult.R33;
		
		//Calculates the second row using the third row.
		tmpFloat = tmpMatrix.R23;
		tmpMatrix.R21	 -= tmpFloat * tmpMatrix.R31;
		tmpMatrix.R22	 -= tmpFloat * tmpMatrix.R32;
		tmpMatrix.R23	 -= tmpFloat * tmpMatrix.R33;
		matrixResult.R21 -= tmpFloat * matrixResult.R31;
		matrixResult.R22 -= tmpFloat * matrixResult.R32;
		matrixResult.R23 -= tmpFloat * matrixResult.R33;


		//Returns matrixResult.
		return matrixResult;
	}

	///<summary>
	///Creates a transpose of this matrix.
	///</summary>
	///<returns>The transpose of this matrix.</returns>
	RAT_Matrix33 RAT_Matrix33::Transpose() const
	{
		//Initializes the matrix that is to be returned.
		RAT_Matrix33 matrixResult;

		//Creates the transpose of this matrix.
		matrixResult.R11 = R11;
		matrixResult.R22 = R22;
		matrixResult.R33 = R33;

		matrixResult.R12 = R21;
		matrixResult.R13 = R31;
		matrixResult.R21 = R12;
		matrixResult.R23 = R32;
		matrixResult.R31 = R13;
		matrixResult.R32 = R23;

		//Returns matrixResult.
		return matrixResult;
	}

	///<summary>
	///Prints the matrix into the IOStream.
	///</summary>
	void RAT_Matrix33::PrintIO()
	{
		std::cout << R11 << ", " << R12 << ", " << R13 << std::endl
				  << R21 << ", " << R22 << ", " << R23 << std::endl
				  << R31 << ", " << R32 << ", " << R33 << std::endl;
	}
}